package com.example.demo.nio;

import org.bson.ByteBuf;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioClient {

    public static void main(String[] args) throws IOException {
        // 获得一个通道，用于连接服务端
        SocketChannel socketChannel = SocketChannel.open();
        // 设置非阻塞
        socketChannel.configureBlocking(false);
        // 获取选择器
        Selector selector = Selector.open();
        // 设置连接ip和端口
        socketChannel.connect(new InetSocketAddress("127.0.0.1",7000));
        // 直接注册好所有需要的事件(因为客户端这边只有一个服务端访问的话就可以直接在这里设置了)
        socketChannel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);

        while(true){
            // 轮询看一下有没有待处理事件
            selector.select();
            // 迭代器处理
            Iterator<SelectionKey> iterator=selector.selectedKeys().iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey=iterator.next();
                // 调用下面的方法处理
                handler(selectionKey);
                iterator.remove();
            }
        }
    }

    private static void handler(SelectionKey selectionKey) throws IOException {
        // 连接事件需要在这里继续处理，先判断一下是否处于已经找到远程连接点并准备就绪(上面的socketChannel.connect就会让它去找对应连接点)
        if(selectionKey.isConnectable()){
            // 转成SocketChannel操作
            SocketChannel channel = (SocketChannel)selectionKey.channel();
            // 如果现在连接是挂起状态则进入并调用finishConnect完成连接(socketChannel.connect找到连接点后会不等结果立刻返回,所以需要用这个来判断现在是否正常的准备连接)
            if(channel.isConnectionPending()){
                long startTime = System.currentTimeMillis();
                while(true){
                    // finishConnect会让连接正式开始并完成,如果连接成功则会返回true，10秒内未成功则结束连接
                    // 调用finishConnect的第一次相当于开始执行连接，后续每次调用都只相当于查看连接是否成功
                    if(channel.finishConnect()){
                        channel.configureBlocking(false);
                        ByteBuffer buffer=ByteBuffer.wrap("qwe".getBytes());
                        channel.write(buffer);
                        break;
                    }else if(System.currentTimeMillis()-startTime>10000){
                        System.out.println("连接超时");
                        break;
                    }
                    System.out.println(System.currentTimeMillis() - startTime);
                }
            }else{
                // 如果失败则做一些处理
                System.out.println("连接已建立或连接失败");
            }

        }else if(selectionKey.isReadable()){
            // 无论读写都需要先转SocketChannel
            SocketChannel channel = (SocketChannel) selectionKey.channel();
            ByteBuffer buffer =ByteBuffer.allocate(1024);
            int len =channel.read(buffer);
            // 看一下读到的内容
            if(len!=-1){
                System.out.println(new String(buffer.array(),0,len));
            }


        }


    }


}
